<?php

declare(strict_types=1);

namespace Zms\Validate\Rule;

use Zms\Unit\Is;
use const FILTER_FLAG_IPV4;
use const FILTER_FLAG_IPV6;
use const FILTER_VALIDATE_IP;

/**
 * IP地址验证类
 * 用于验证输入值是否为有效的IPv4或IPv6地址，并支持指定IP类型。
 */
class IpValidate extends RuleAbstract
{
    /**
     * 默认错误信息
     * 当验证失败时返回的错误信息模板。
     * @var string
     */
    protected $_error = '{label}不是有效的IP';

    /**
     * 验证IP地址的类型
     * 可选值为 'ipv4' 或 'ipv6'，默认为空表示不指定类型。
     * @var string
     */
    protected $_type;

    /**
     * IP地址类型错误提示
     * 当指定的IP类型验证失败时返回的错误信息模板。
     * @var string
     */
    protected $_typeError = "{label}不是{type}类型IP地址";

    /**
     * 设置IP类型验证
     * 指定验证的IP类型为 'ipv4' 或 'ipv6'。
     * @param string $type IP类型
     * @return $this
     */
    public function setType(string $type): IpValidate
    {
        $this->_type = strtolower($type);
        return $this;
    }

    /**
     * 设置IP类型验证错误信息
     * 自定义指定类型验证失败时的错误信息。
     * @param string $error 自定义错误信息
     * @return $this
     */
    public function setTypeError(string $error): IpValidate
    {
        $this->_typeError = $error;
        return $this;
    }

    /**
     * 验证IP地址
     * 使用 PHP 的 `filter_var` 函数和 `FILTER_VALIDATE_IP` 过滤器验证IP地址。
     * 如果指定了IP类型，则根据类型进行验证。
     * @param mixed $value 输入值
     * @param string $label 验证名（用于错误信息中）
     * @return bool 验证结果
     */
    public function validate($value, string $label = ''): bool
    {
        // 确保输入值是字符串类型
        if (is_string($value)) {
            // 如果值为空且 `_noSkipping` 为 true，则直接返回 true
            if (Is::empty($value) && $this->_noSkipping === true) {
                $this->_value = $value;
                return true;
            }

            // 根据指定的IP类型进行验证
            switch ($this->_type) {
                case 'ipv4':
                    // 验证是否为有效的IPv4地址
                    if (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
                        $this->_value = $value;
                        return true;
                    }
                    // 添加类型错误信息
                    $this->addError($this->_typeError ?: '{label}不是有效的ipv4地址', $label);
                    break;

                case 'ipv6':
                    // 验证是否为有效的IPv6地址
                    if (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
                        $this->_value = $value;
                        return true;
                    }
                    // 添加类型错误信息
                    $this->addError($this->_typeError ?: '{label}不是有效的ipv6地址', $label);
                    break;

                default:
                    // 不指定类型，验证是否为有效的IP地址（IPv4或IPv6）
                    if (filter_var($value, FILTER_VALIDATE_IP)) {
                        $this->_value = $value;
                        return true;
                    }
            }
        }

        // 如果验证失败，添加默认错误信息并返回 false
        return $this->addError($this->_error, $label);
    }
}
